/***************************************************************************
 *   Copyright (C) 2006 by Grzegorz Latarowski                             *
 *   g.latarowski@gmail.com                                                *
 *                                                                         *
 *   Project: AutoStop (kodowa nazwa do zmiany)                            *
 *                                                                         *
 ***************************************************************************/


#ifndef SORTFILTERPROXYMODELS_H
#define SORTFILTERPROXYMODELS_H

#include <QtGui>
 

#define INFINITY 999999999.0


enum FilterModelTypes {
    qSortFilterProxtModel = 0x0,
    filterModel = 0x1,
    globalSortFilterProxyModel = 0x2,
    dateSortFilterProxyModel = 0x4,
    regExpSortFilterProxyModel = 0x8,
    doubleSortFilterProxyModel = 0x16,
    multiTypeSortFilterProxyModel = 0x32
};




// ---------------------------------------------------------------------------
/*!
 * Klasa bazowa dla wszystkich modeli proxy.
 */
// ---------------------------------------------------------------------------
class FilterModel : public QSortFilterProxyModel
{
Q_OBJECT;

public:
        /*!
        * Konstruktor.
        */
    FilterModel(QObject * parent = 0) : QSortFilterProxyModel(parent)
    {}
    
    virtual bool acceptsRow(int, const QModelIndex &) const
    {
        return true;
    }
    
protected:
    bool filterAcceptsRow(int, const QModelIndex &)const
    {
        return true;
    }
    
}; // class FilterModel
// ---------------------------------------------------------------------------




// ---------------------------------------------------------------------------
/*!
 * Ten proxyModel filtruje całą zawartość modelu poprzez ignorowanie
 * \e filterKeyColumn.
 */
// ---------------------------------------------------------------------------
class GlobalSortFilterProxyModel : public FilterModel
{
Q_OBJECT;

public:
        /*!
        * Konstruktor.
        */
    GlobalSortFilterProxyModel(QObject * parent = 0);
    
    bool acceptsRow(int sourceRow, const QModelIndex & sourceParent) const;
protected:
    bool filterAcceptsRow(int sourceRow, const QModelIndex & sourceParent) const;
    
    
}; // class GlobalSortFilterProxyModel
    
/// Operator odczytu
QDataStream & operator >> (QDataStream & in, GlobalSortFilterProxyModel *);
/// Operator zapisu
QDataStream & operator << (QDataStream & out, const GlobalSortFilterProxyModel *);
// ---------------------------------------------------------------------------




// ---------------------------------------------------------------------------
/*!
 * Ten proxyModel filtruje zawartość modelu ze względu na date.
 * Jeśli data indexu mieści się w ustawionym przedziale to ok.
 */
// ---------------------------------------------------------------------------
class DateSortFilterProxyModel : public FilterModel
{
Q_OBJECT;

public:
        /*!
        * Konstruktor.
        */
    DateSortFilterProxyModel(QObject * parent = 0);
    
        /*!
        * Ustawia dolne ograniczenie.
        */
    void setLowerBound(const QDate lowerBound);
        /*!
        * Ustawia górne ograniczenie.
        */
    void setUpperBound(const QDate upperBound);
        /*!
        * Zwraca dolne ograniczenie.
        */
    QDate lowerBound()const { return _lowerBound; }
        /*!
        * Zwraca górne ograniczenie.
        */
    QDate upperBound()const { return _upperBound; }
        /*!
        * Jeśli \e dateTime mieści się w przedziale pomiędzy dolnym
        * a górnym ograniczeniem to zwraca true w przeciwnym wypadku false.
        */
    bool dateInRange(const QDate date)const;
    
    bool acceptsRow(int sourceRow, const QModelIndex & sourceParent) const;    
    
public slots:
        /*!
        * Przywraca dolne ograniczenie na 1900.01.01
        */
    void clearLowerBound();
        /*!
        * Przywraca górne ograniczenie na 3000.01.01
        */
    void clearUpperBound();
        /*!
        * Przywraca domyślne dolne i górne ogranicznie.
        */
    void clear();
    
protected:
    bool filterAcceptsRow(int sourceRow, const QModelIndex & sourceParent)const;

private:
        /// Dolne ograniczenie
    QDate _lowerBound;
        /// Górne ograniczenie
    QDate _upperBound;
}; //class DateSortFilterProxyModel
    
/// Operator odczytu
QDataStream & operator >> (QDataStream & in, DateSortFilterProxyModel *);
/// Operator zapisu
QDataStream & operator << (QDataStream & out, const DateSortFilterProxyModel *);
// ---------------------------------------------------------------------------




// ---------------------------------------------------------------------------
/*!
* Ten proxyModel filtruje zawartość modelu używając OR dla kilku kolumn.
 */
// ---------------------------------------------------------------------------
class RegExpSortFilterProxyModel : public FilterModel
{
Q_OBJECT;

public:
        /*!
        * Konstruktor.
        */
    RegExpSortFilterProxyModel(QObject * parent = 0);
        /*!
        * Dodaje \e regExp do listy wyrażeń ale najpierw czyści tą liste.
        */
    void setFilterRegExp(const QRegExp & regExp);
    QRegExp filterRegExp()const { return _regExp; }
    
    bool acceptsRow(int sourceRow, const QModelIndex & sourceParent) const;
    
protected:
        /*!
        * Filtruje komórki biorąc numer kolumny z listy \e _columnList
        * i z odpowiedniej pozycji filtr z listy \e _regExpList. Przy filtrowaniu
        * pod uwagę bierze tyle kolumn ile jest na liście \e _columnList lub jeżeli
        * lista \e _regExpList ma mniejszy rozmiar to tyle ile jest w \e _regExpList.
        * Jeśli komórka zaakceptowana to zwraca true a jeśli nie to false.
        */
    bool filterAcceptsRow(int sourceRow, const QModelIndex & sourceParent) const;

private:
        /// Lista wyrażeń regularnych dla każdej kolumny. Wyrażenie na itej
        /// pozycji odpowiada kolumnie na itej pozycji w _columnList.
    QRegExp _regExp;
    

}; //cass RegExpSortFilterProxyModel

/// Operator odczytu
QDataStream & operator >> (QDataStream & in, RegExpSortFilterProxyModel *);
/// Operator zapisu
QDataStream & operator << (QDataStream & out, const RegExpSortFilterProxyModel *);
// ---------------------------------------------------------------------------




// ---------------------------------------------------------------------------
/*!
 * Ten proxyModel filtruje zawartość modelu używając OR dla kilku kolumn.
 */
// ---------------------------------------------------------------------------
class DoubleSortFilterProxyModel : public FilterModel
{
Q_OBJECT;

public:
        /*!
        * Konstruktor.
        */
    DoubleSortFilterProxyModel(QObject * parent = 0);    
        /*!
        * Ustawia dolne ograniczenie.
        */
    void setLowerBound(const qreal lowerBound);
        /*!
        * Ustawia górne ograniczenie.
        */
    void setUpperBound(const qreal upperBound);
        /*!
        * Zwraca dolne ograniczenie.
        */
    qreal lowerBound()const { return _lowerBound; }
        /*!
        * Zwraca górne ograniczenie.
        */
    qreal upperBound()const { return _upperBound; }
        /*!
        * Jeśli \e number mieści się w przedziale pomiędzy dolnym
        * i górnym ograniczeniem to zwraca true w przeciwnym razie false.
        */
    bool numberInRange(const double number)const;
    
    bool acceptsRow(int sourceRow, const QModelIndex & sourceParent) const;
    
protected:
    bool filterAcceptsRow(int sourceRow, const QModelIndex & sourceParent)const;

private:
        /// Dolne ograniczenie
    qreal _lowerBound;
        /// Górne ograniczenie
    qreal _upperBound;

}; // class DoubleSortFilterProxyModel

/// Operator odczytu
QDataStream & operator >> (QDataStream & in, DoubleSortFilterProxyModel *);
/// Operator zapisu
QDataStream & operator << (QDataStream & out, const DoubleSortFilterProxyModel *);
// ---------------------------------------------------------------------------




// ---------------------------------------------------------------------------
/*!
 * Ten proxyModel filtruje zawartość modelu używając OR dla kilku kolumn.
 */
// ---------------------------------------------------------------------------
class MultiTypeSortFilterProxyModel : public FilterModel
{
Q_OBJECT;

public:
        /*!
        * Konstruktor.
        */
    MultiTypeSortFilterProxyModel(QObject * parent = 0);
        /*!
        * Destruktor.
        */
    ~MultiTypeSortFilterProxyModel();
    
    bool acceptsRow(int sourceRow, const QModelIndex & sourceParent)const;
    void setSourceModel(QAbstractItemModel * sourceModel);            
    QList<FilterModel *> patternModelList() const { return _patternModelList; }
    int patternModelListSize() { return _patternModelList.size(); }
    
public slots:
        /*!
        * Czyści liste modeli i dodaje \e pattern model do czystej listy.
        */
    void setPatternModel(FilterModel *patternModel);
        /*!
        * Ustawia liste modeli.
        */
    void setPatternModels(const QList<FilterModel *> patternModelList);
        /*!
        * Czyści model.
        */
    void clear();
    
protected:
    bool filterAcceptsRow(int sourceRow, const QModelIndex & sourceParent)const;

private:
    QList<FilterModel *> _patternModelList;
    
//     QAbstractItemModel *_sourceModel;
    
}; //class MultiTypeSortFilterProxyModel

/// Operator odczytu
QDataStream & operator >> (QDataStream & in, MultiTypeSortFilterProxyModel *);
/// Operator zapisu
QDataStream & operator << (QDataStream & out, const MultiTypeSortFilterProxyModel *);
// ---------------------------------------------------------------------------









// ---------------------------------------------------------------------------
/*!
 * Klasa kompleksowego modelu filtra.
 */
// ---------------------------------------------------------------------------
class Filter : public FilterModel, public QListWidgetItem
{
    Q_OBJECT
    public:
        /*!
     * Konstruktor.
         */
        Filter(QObject * parent = 0, int type = Type);
        /*!
         * Konstruktor kopiujący.
         */
        Filter(const QString & text, QObject * parent = 0, int type = Type);
        /*!
         * Konstruktor kopiujący.
         */
        Filter(const QIcon & icon, const QString & text, QObject * parent = 0, int type = Type);
    
        /*!
         * Destruktor.
         * Usuwa wszystkie modele z listy _modelsList.
         */
        ~Filter();
    
        /*!
         * Usuwa wszystkie modele z listy _modelsList.
         */
        void clearModelsList();
        /*!
         * Zwraca ilość modeli w filtrze.
         */
        quint32 modelsCount() const { return _modelsList.size(); }
        /*!
         * Zwraca listę modeli w filtrze.
         */
        QList<MultiTypeSortFilterProxyModel *> modelsList() const { return _modelsList; }
    
        bool acceptsRow(int sourceRow, const QModelIndex & sourceParent)const;
    
    public slots:    
        /*!
     * Ustawia dla wszysttkich modeli z list _modelsList
     * ten sam źródłowy model danych.
         */
        void setSourceModel(QAbstractItemModel * sourceModel);
        /*!
         * Dodaj filtrujący model do filtra.
         */
        void addModel(MultiTypeSortFilterProxyModel *model);
    
    protected:
        bool filterAcceptsRow(int sourceRow, const QModelIndex & sourceParent)const;
        
    private:
        /// lista modeli filtrujących
        QList<MultiTypeSortFilterProxyModel *> _modelsList;
    
}; // class Filter

/// Operator odczytu
QDataStream & operator >> (QDataStream & in, Filter *);
/// Operator zapisu
QDataStream & operator << (QDataStream & out, const Filter *);
// ---------------------------------------------------------------------------




#endif // SORTFILTERPROXYMODEL_H








